/*
 * To change this license header, choose License Headers in Project Properties.
 * To change this template file, choose Tools | Templates
 * and open the template in the editor.
 */
package gui.components.basic.gui.logic;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.logging.Level;
import java.util.logging.Logger;

/**
 *
 * @author Luca
 */
public class CRUDCentral {

    private static CRUDCentral _instance = null;
    private Map<Class<?>, Object> crudFacadeMap = new HashMap<Class<?>, Object>();
    private List<CRUDUpdateEntityListener> updateListeners = new ArrayList<CRUDUpdateEntityListener>();

    public static CRUDCentral getInstance() {
        if (_instance == null) {
            _instance = new CRUDCentral();
            return _instance;
        } else {
            return _instance;
        }
    }

    private CRUDCentral() {
        super();
//        this.addFacade(Person.class, new PersonJpaController(Persistence.createEntityManagerFactory("dbAnagBasePU")));
//        this.addFacade(IDDocument.class, new IDDocumentJpaController(Persistence.createEntityManagerFactory("dbAnagBasePU")));
//        this.addFacade(MongoDocument.class, new MongoDocumentJpaController(Persistence.createEntityManagerFactory("nosqlDBPU")));
    }
    
    public void addCRUDUpdateEntityListener(CRUDUpdateEntityListener listener){
        this.updateListeners.add(listener);
    }
    
    public void updateMe(Class<?> entityClazz, Object id){
        System.out.println("spamming update order");
        for (CRUDUpdateEntityListener cRUDUpdateEntityListener : updateListeners) {
            System.out.println("spammed!");
            cRUDUpdateEntityListener.updateThisEntity(entityClazz, id);
        }
    }
    
    public void entitySelected(Object entity){
        for (CRUDUpdateEntityListener listener : updateListeners) {
            listener.entitySelected(entity);
        }
    }

    public void addFacade(Class<?> forClazz, Object facade) {
        this.crudFacadeMap.put(forClazz, facade);
    }
    
    
    public <T> List<T> findAllEntities(Class<T> clazz){
        if (this.crudFacadeMap.containsKey(clazz)) {
            try {
                String clazzFullName = clazz.getName();
                String[] split = clazzFullName.split("\\.");
                Method method = this.crudFacadeMap.get(clazz).getClass().getMethod("find"+split[split.length-1]+"Entities");
                List<T> list = (List<T>) method.invoke(this.crudFacadeMap.get(clazz));
                System.out.println("invocato");
                return list;
            } catch (NoSuchMethodException ex) {
                Logger.getLogger(CRUDCentral.class.getName()).log(Level.SEVERE, null, ex);
            } catch (SecurityException ex) {
                Logger.getLogger(CRUDCentral.class.getName()).log(Level.SEVERE, null, ex);
            } catch (IllegalAccessException ex) {
                Logger.getLogger(CRUDCentral.class.getName()).log(Level.SEVERE, null, ex);
            } catch (IllegalArgumentException ex) {
                Logger.getLogger(CRUDCentral.class.getName()).log(Level.SEVERE, null, ex);
            } catch (InvocationTargetException ex) {
                Logger.getLogger(CRUDCentral.class.getName()).log(Level.SEVERE, null, ex);
            }
        } else {
            System.out.println("Impossible to fiun this entities.");
            return null;
        }
        return null;
    }
    
    public Object findEntity(Class<?> clazz, Object id) {
        if (this.crudFacadeMap.containsKey(clazz)) {
            try {
                String clazzFullName = clazz.getName();
                String[] split = clazzFullName.split("\\.");
                Method method = this.crudFacadeMap.get(clazz).getClass().getMethod("find"+split[split.length-1], id.getClass());
                Object entityFound = method.invoke(this.crudFacadeMap.get(clazz), id);
                System.out.println("invocato");
                return entityFound;
            } catch (NoSuchMethodException ex) {
                Logger.getLogger(CRUDCentral.class.getName()).log(Level.SEVERE, null, ex);
            } catch (SecurityException ex) {
                Logger.getLogger(CRUDCentral.class.getName()).log(Level.SEVERE, null, ex);
            } catch (IllegalAccessException ex) {
                Logger.getLogger(CRUDCentral.class.getName()).log(Level.SEVERE, null, ex);
            } catch (IllegalArgumentException ex) {
                Logger.getLogger(CRUDCentral.class.getName()).log(Level.SEVERE, null, ex);
            } catch (InvocationTargetException ex) {
                Logger.getLogger(CRUDCentral.class.getName()).log(Level.SEVERE, null, ex);
            }
        } else {
            System.out.println("Impossible to store this entity.");
            return null;
        }
        return null;
    }

    public void saveEntity(Object entity) {
        if (this.crudFacadeMap.containsKey(entity.getClass())) {
            try {
                Method method = this.crudFacadeMap.get(entity.getClass()).getClass().getMethod("create", entity.getClass());
                method.invoke(this.crudFacadeMap.get(entity.getClass()), entity);
                System.out.println("salvato");
                for (CRUDUpdateEntityListener lll : updateListeners) {
                    lll.newEntity(entity);
                }
            } catch (NoSuchMethodException ex) {
                Logger.getLogger(CRUDCentral.class.getName()).log(Level.SEVERE, null, ex);
            } catch (SecurityException ex) {
                Logger.getLogger(CRUDCentral.class.getName()).log(Level.SEVERE, null, ex);
            } catch (IllegalAccessException ex) {
                Logger.getLogger(CRUDCentral.class.getName()).log(Level.SEVERE, null, ex);
            } catch (IllegalArgumentException ex) {
                Logger.getLogger(CRUDCentral.class.getName()).log(Level.SEVERE, null, ex);
            } catch (InvocationTargetException ex) {
                Logger.getLogger(CRUDCentral.class.getName()).log(Level.SEVERE, null, ex);
            }
        } else {
            System.out.println("Impossible to store this entity.");
        }
    }
    
    
    
    public void updateEntity(Object entity) {
        if (this.crudFacadeMap.containsKey(entity.getClass())) {
            try {
                Method method = this.crudFacadeMap.get(entity.getClass()).getClass().getMethod("edit", entity.getClass());
                method.invoke(this.crudFacadeMap.get(entity.getClass()), entity);
                System.out.println("update OK");
            } catch (NoSuchMethodException ex) {
                Logger.getLogger(CRUDCentral.class.getName()).log(Level.SEVERE, null, ex);
            } catch (SecurityException ex) {
                Logger.getLogger(CRUDCentral.class.getName()).log(Level.SEVERE, null, ex);
            } catch (IllegalAccessException ex) {
                Logger.getLogger(CRUDCentral.class.getName()).log(Level.SEVERE, null, ex);
            } catch (IllegalArgumentException ex) {
                Logger.getLogger(CRUDCentral.class.getName()).log(Level.SEVERE, null, ex);
            } catch (InvocationTargetException ex) {
                Logger.getLogger(CRUDCentral.class.getName()).log(Level.SEVERE, null, ex);
            }
        } else {
            System.out.println("Impossible to store this entity.");
        }

    }
}

